#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>
#include <cstring>

#include "Log.hpp"

using namespace LogMoudle;

class UdpSocket
{
public:
    UdpSocket()
    :_fd(-1)
    {}
    ~UdpSocket()
    {}
    bool Socket()
    {
        _fd=socket(AF_INET,SOCK_DGRAM,0);
        if(_fd<0)
        {
           LOG(LogLevel::FATAL)<<"socket error";
            return false;
        }
        return true;
    }
    bool Close()
    {
        close(_fd);
        return true;
    }
    bool Bind(const std::string& ip,uint16_t port)
    {
        sockaddr_in addr;
        memset(&addr,0,sizeof(addr));
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=inet_addr(ip.c_str());
        int ret=bind(_fd,(struct sockaddr*)&addr,sizeof(addr));
        if(ret<0)
        {
            LOG(LogLevel::FATAL)<<"bind error";
            return false;
        }
        return true;
    }
    bool RecvFrom(std::string* buf,std::string* ip=NULL,uint16_t* port=NULL)
    {
        char tmp[1024*10]={0};
        sockaddr_in peer;
        memset(&peer,0,sizeof(peer));
        socklen_t len=sizeof(peer);
        int n=recvfrom(_fd,tmp,sizeof(tmp)-1,0,(struct sockaddr*)&peer,&len);
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"recvfrom error";
            return false;
        }
        // 将读到的数据放入输出参数中
        buf->assign(tmp,n);
        if(ip!=NULL)
        {
            *ip=inet_ntoa(peer.sin_addr);
        }
        if(port!=NULL)
        {
            *port=ntohs(peer.sin_port);
        }
        return true;
    }
    bool Sendto(const std::string& buf,std::string& ip,uint16_t port)
    {
        sockaddr_in addr;
        memset(&addr,0,sizeof(addr));
        addr.sin_addr.s_addr=inet_addr(ip.c_str());
        addr.sin_port=htons(port);
        addr.sin_family=AF_INET;
        ssize_t n=sendto(_fd,buf.c_str(),sizeof(buf),0,(const sockaddr*)&addr,sizeof(addr));
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"sendto error";
            return false;
        }
        return true;
    }
private:
    int _fd;
};